package io.gitee.cengxiaoxiao.wrapper;

import cn.idev.excel.FastExcel;
import cn.idev.excel.converters.localdate.LocalDateStringConverter;
import cn.idev.excel.converters.localdatetime.LocalDateTimeStringConverter;
import cn.idev.excel.read.builder.ExcelReaderBuilder;
import cn.idev.excel.read.listener.ReadListener;
import io.gitee.cengxiaoxiao.converters.LocalTimeConverter;
import io.gitee.cengxiaoxiao.exceptions.ExcelException;
import io.gitee.cengxiaoxiao.tools.ExcelUtil;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Excel读取工具类
 * 包装fastexcel的读取方法，提供更简便的使用方式
 */
public class ExcelReadWrapper {
    private static final ExcelReaderBuilder BaseBuilder = FastExcel.read()
            .charset(StandardCharsets.UTF_8)
            .registerConverter(LocalTimeConverter.INSTANCE())
            .registerConverter(new LocalDateStringConverter())
            .registerConverter(new LocalDateTimeStringConverter());


    /**
     * 读取Excel
     *
     * @param file  文件
     * @param clazz Excel表头类型
     * @param <S>   Excel表头类型
     * @return 表头类型对象列表
     */
    public static <S> List<S> read(File file, Class<S> clazz) {
        return read(file, clazz, 0);
    }

    public static <S> List<S> read(File file, Class<S> clazz, int sheetNo) {
        ExcelUtil.checkFile(file);
        try (FileInputStream inputStream = new FileInputStream(file)) {
            return read(inputStream, clazz, sheetNo);
        } catch (IOException e) {
            throw new ExcelException(e);
        }
    }

    /**
     * 读取Excel, 并转换为目标对象
     *
     * @param filepath 文件路径
     * @param head     Excel表头类型
     * @param target   目标类型
     * @param <S>      Excel表头类型
     * @param <T>      目标类型
     * @return 目标对象列表
     */
    public static <S, T> List<T> read(String filepath, Class<S> head, Class<T> target) {
        File file = ExcelUtil.getExcelFile(filepath);
        try (FileInputStream inputStream = new FileInputStream(file)) {
            List<S> sourceList = BaseBuilder.file(inputStream)
                    .head(head)
                    .sheet(0)
                    .doReadSync();
            return sourceList.stream()
                    .map(item -> ExcelUtil.copy(item, target))
                    .collect(Collectors.toList());
        } catch (IOException e) {
            throw new ExcelException(e);
        }
    }

    /**
     * 读取Excel,返回列表
     *
     * @param is   输入流
     * @param head Excel表头类型
     * @param <S>  Excel表头类型
     * @return 表头类型对象列表
     */
    public static <S> List<S> read(InputStream is, Class<S> head) {
        return read(is, head, 0);
    }

    /**
     * 读取Excel,返回列表
     *
     * @param is      输入流
     * @param head    Excel表头类型
     * @param sheetNo sheet序号
     * @param <S>     Excel表头类型
     * @return 表头类型对象列表
     */
    public static <S> List<S> read(InputStream is, Class<S> head, int sheetNo) {
        List<S> list = BaseBuilder.file(is)
                .head(head)
                .sheet(sheetNo)
                .doReadSync();
        list.forEach(ExcelUtil::dictConvert);
        return list;
    }

    public static <S> void read(File file, ReadListener<S> readListener) {
        read(file, null, readListener);
    }

    public static <S> void read(File file, Class<S> clazz, ReadListener<S> readListener) {
        if (file == null) {
            throw new IllegalArgumentException("文件不能为空");
        }
        if (file.exists() && file.isFile()) {
            try (FileInputStream inputStream = new FileInputStream(file)) {
                read(inputStream, clazz, 0, readListener);
            } catch (IOException e) {
                throw new ExcelException(e);
            }
        }

    }

    public static <S> void read(String filepath, ReadListener<S> readListener) {
        File file = ExcelUtil.getExcelFile(filepath);
        try (FileInputStream inputStream = new FileInputStream(file)) {
            read(inputStream, null, 0, readListener);
        } catch (IOException e) {
            throw new ExcelException(e);
        }
    }

    /**
     * 读取Excel, 根据readListener执行操作
     *
     * @param filepath     文件路径
     * @param clazz        Excel表头类型
     * @param readListener 读取监听器
     * @param <S>          Excel表头类型
     */
    public static <S> void read(String filepath, Class<S> clazz, ReadListener<S> readListener) {
        File file = ExcelUtil.getExcelFile(filepath);
        try (FileInputStream inputStream = new FileInputStream(file)) {
            read(inputStream, clazz, 0, readListener);
        } catch (IOException e) {
            throw new ExcelException(e);
        }
    }

    /**
     * 读取Excel, 根据readListener执行操作
     *
     * @param is
     * @param clazz
     * @param readListener
     * @param <S>
     */
    public static <S> void read(InputStream is, Class<S> clazz, ReadListener<S> readListener) {
        read(is, clazz, 0, readListener);
    }

    public static <S> void read(InputStream is, Class<S> head, int sheetNo, ReadListener<S> readListener) {
        if (is == null) {
            throw new IllegalArgumentException("输入的文件流不能为空");
        }
        if (readListener == null) {
            throw new IllegalArgumentException("读取监听器不能为空");
        }
        if (sheetNo < 0) {
            sheetNo = 0;
        }
        BaseBuilder.file(is)
                .head(head)
                .registerReadListener(readListener)
                .autoCloseStream(true)
                .sheet(sheetNo)
                .doRead();
    }
}
